package org.example.kpi;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;

/**
 * KPI对象类，用于解析和处理日志数据，提取关键性能指标。
 */
public class KPI {
	private String remote_addr;// 记录客户端的ip地址
	private String remote_user;// 记录客户端用户名称,忽略属性"-"
	private String time_local;// 记录访问时间与时区
	private String request;// 记录请求的url与http协议
	private String status;// 记录请求状态；成功是200
	private String body_bytes_sent;// 记录发送给客户端文件主体内容大小
	private String http_referer;// 用来记录从那个页面链接访问过来的
	private String http_user_agent;// 记录客户浏览器的相关信息

	private boolean valid = true;// 判断数据是否合法

	/**
	 * 解析日志行，将其转换为KPI对象。
	 *
	 * @param line 一个包含日志信息的字符串，格式应与特定日志文件格式相匹配。
	 * @return 返回一个KPI对象，该对象根据日志行信息进行了初始化。
	 */
	private static KPI parser(String line) {
	    KPI kpi = new KPI();
	    String[] arr = line.split(" ");
	    // 判断日志行是否包含足够的信息
	    if (arr.length > 11) {
	        // 设置KPI对象的基本信息
	        kpi.setRemote_addr(arr[0]);
	        kpi.setRemote_user(arr[1]);
	        kpi.setTime_local(arr[3].substring(1));
	        kpi.setRequest(arr[6]);
	        kpi.setStatus(arr[8]);
	        kpi.setBody_bytes_sent(arr[9]);
	        kpi.setHttp_referer(arr[10]);

	        // 如果存在用户代理信息，则合并设置
	        if (arr.length > 12) {
	            kpi.setHttp_user_agent(arr[11] + " " + arr[12]);
	        } else {
	            kpi.setHttp_user_agent(arr[11]);
	        }

	        // 根据HTTP状态码判断请求是否有效
	        if (Integer.parseInt(kpi.getStatus()) >= 400) {
	            kpi.setValid(false);
	        }
	    } else {
	        // 如果日志行信息不足，标记KPI对象为无效
	        kpi.setValid(false);
	    }
	    return kpi;
	}

	/**
	 * 根据页面访问量（PV）对请求进行分类
	 *
	 * @param line 包含PV信息的字符串
	 * @return 经过筛选后的KPI对象，如果请求的页面不在预定义的页面集合中，则将该KPI标记为无效
	 */
	public static KPI filterPVs(String line) {
	    // 解析输入字符串，获取KPI信息
	    KPI kpi = parser(line);
	    // 预定义的有效页面集合
	    Set<String> pages = new HashSet<String>();
	    pages.add("/about");
	    pages.add("/black-ip-list/");
	    pages.add("/cassandra-clustor/");
	    pages.add("/finance-rhive-repurchase/");
	    pages.add("/hadoop-family-roadmap/");
	    pages.add("/hadoop-hive-intro/");
	    pages.add("/hadoop-zookeeper-intro/");
	    pages.add("/hadoop-mahout-roadmap/");
	    // 检查请求的页面是否在预定义的有效页面集合中，若不在则标记KPI为无效
	    if (!pages.contains(kpi.getRequest())) {
	        kpi.setValid(false);
	    }
	    return kpi;
	}

	/**
	 * 根据页面的独立IP进行分类过滤。
	 * <p>
	 * 对输入的字符串行进行解析，并检查解析后的请求是否指向指定的页面集合中的一个页面。
	 * 如果请求的页面不在指定的页面集合内，则将KPI的有效性标记为false。
	 *
	 * @param line 输入的字符串行，预期为包含访问信息的日志条目。
	 * @return 经过过滤和标记有效性的KPI对象。
	 */
	public static KPI filterIPs(String line) {
	    // 解析输入行以获取KPI指标
	    KPI kpi = parser(line);
	    // 定义一个页面集合，包含需要过滤的特定页面URL
	    Set<String> pages = new HashSet<String>();
	    pages.add("/about");
	    pages.add("/black-ip-list/");
	    pages.add("/cassandra-clustor/");
	    pages.add("/finance-rhive-repurchase/");
	    pages.add("/hadoop-family-roadmap/");
	    pages.add("/hadoop-hive-intro/");
	    pages.add("/hadoop-zookeeper-intro/");
	    pages.add("/hadoop-mahout-roadmap/");
	    // 检查请求的页面是否在指定的页面集合内，若不在则标记KPI为无效
	    if (!pages.contains(kpi.getRequest())) {
	        kpi.setValid(false);
	    }
	    return kpi;
	}

	/**
	 * 根据浏览器对PV进行分类
	 * @param line 表示一条记录，需要被解析以确定其属于哪个浏览器的PV
	 * @return 返回一个KPI对象，该对象包含了根据浏览器分类的PV信息
	 */
	public static KPI filterBroswer(String line) {
	    return parser(line); // 解析输入行并返回相应的KPI对象
	}

	/**
	 * 将输入的字符串按小时分类处理并返回KPI对象。
	 *
	 * @param line 输入的字符串，预期为某种日志或数据行。
	 * @return KPI 返回处理后的KPI对象，包含了按小时分类的数据统计。
	 */
	public static KPI filterTime(String line) {
	    return parser(line); // 调用parser方法，处理并返回KPI对象
	}

	/**
	 * 根据访问域名对PV进行分类
	 *
	 * @param line 表示一条访问记录的字符串，需要解析以获取域名信息
	 * @return 返回解析后的KPI对象，其中包含了按域名分类的PV信息
	 */
	public static KPI filterDomain(String line) {
	    return parser(line); // 解析输入字符串并返回KPI对象
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("valid:" + this.valid);
		sb.append("\nremote_addr:" + this.remote_addr);
		sb.append("\nremote_user:" + this.remote_user);
		sb.append("\ntime_local:" + this.time_local);
		sb.append("\nrequest:" + this.request);
		sb.append("\nstatus:" + this.status);
		sb.append("\nbody_bytes_sent:" + this.body_bytes_sent);
		sb.append("\nhttp_referer:" + this.http_referer);
		sb.append("\nhttp_user_agent:" + this.http_user_agent);
		return sb.toString();
	}

	public String getRemote_addr() {
		return remote_addr;
	}

	public void setRemote_addr(String remote_addr) {
		this.remote_addr = remote_addr;
	}

	public String getRemote_user() {
		return remote_user;
	}

	public void setRemote_user(String remote_user) {
		this.remote_user = remote_user;
	}

	public String getTime_local() {
		return time_local;
	}

	public Date getTime_local_Date() throws ParseException {
		SimpleDateFormat df = new SimpleDateFormat("dd/MMM/yyyy:HH:mm:ss", Locale.US);
		return df.parse(this.time_local);
	}

	public String getTime_local_Date_hour() throws ParseException {
		SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHH");
		return df.format(this.getTime_local_Date());
	}

	public void setTime_local(String time_local) {
		this.time_local = time_local;
	}

	public String getRequest() {
		return request;
	}

	public void setRequest(String request) {
		this.request = request;
	}

	public String getStatus() {
		return status;
	}

	public void setStatus(String status) {
		this.status = status;
	}

	public String getBody_bytes_sent() {
		return body_bytes_sent;
	}

	public void setBody_bytes_sent(String body_bytes_sent) {
		this.body_bytes_sent = body_bytes_sent;
	}

	public String getHttp_referer() {
		return http_referer;
	}

	/**
	 * 获取HTTP请求的引用域名。
	 * 该方法处理http_referer字符串，移除其中的"http://"或"https://"前缀，以及任何引号，并返回不包含路径部分的域名。
	 * 如果http_referer长度小于8个字符，将原样返回。
	 *
	 * @return String 表示HTTP请求引用的域名。如果原始http_referer包含路径，则返回不包含路径的域名；如果不包含路径，则返回整个http_referer字符串。
	 */
	public String getHttp_referer_domain() {
	    // 如果http_referer长度小于8，直接返回http_referer
	    if (http_referer.length() < 8) {
	        return http_referer;
	    }

	    // 移除http_referer中的引号、http://和https://
	    String str = this.http_referer.replace("\"", "").replace("http://", "").replace("https://", "");
	    // 如果str中包含路径，则返回不包含路径的域名部分；否则，返回整个str
	    return str.indexOf("/") > 0 ? str.substring(0, str.indexOf("/")) : str;
	}

	public void setHttp_referer(String http_referer) {
		this.http_referer = http_referer;
	}

	public String getHttp_user_agent() {
		return http_user_agent;
	}

	public void setHttp_user_agent(String http_user_agent) {
		this.http_user_agent = http_user_agent;
	}

	public boolean isValid() {
		return valid;
	}

	public void setValid(boolean valid) {
		this.valid = valid;
	}

	/**
	 * 主函数，用于解析日志线条并展示关键性能指标（KPI）。
	 *
	 * @param args 命令行参数，此程序不需要传入参数。
	 */
	public static void main(String args[]) {
	    // 示例日志线条
	    String line = "222.68.172.190 - - [18/Sep/2013:06:49:57 +0000] \"GET /images/my.jpg HTTP/1.1\" 200 19939 \"http://www.chinasofti.com\" \"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.1547.66 Safari/537.36\"";
	    System.out.println(line);

	    // 创建KPI实例并解析日志线条
	    KPI kpi = new KPI();
	    String[] arr = line.split(" ");

	    // 解析日志并设置KPI相关属性
	    kpi.setRemote_addr(arr[0]);
	    kpi.setRemote_user(arr[1]);
	    kpi.setTime_local(arr[3].substring(1));
	    kpi.setRequest(arr[6]);
	    kpi.setStatus(arr[8]);
	    kpi.setBody_bytes_sent(arr[9]);
	    kpi.setHttp_referer(arr[10]);
	    kpi.setHttp_user_agent(arr[11] + " " + arr[12]);
	    System.out.println(kpi);

	    // 对KPI实例进行进一步的日期和域名解析
	    try {
	        SimpleDateFormat df = new SimpleDateFormat("yyyy.MM.dd:HH:mm:ss", Locale.US);
	        // 解析并显示本地时间
	        System.out.println(df.format(kpi.getTime_local_Date()));
	        // 显示小时信息
	        System.out.println(kpi.getTime_local_Date_hour());
	        // 解析并显示引用域名
	        System.out.println(kpi.getHttp_referer_domain());
	    } catch (ParseException e) {
	        e.printStackTrace();
	    }
	}

}
